package cn.schoolwow.util.module.query.queryPackage.flow;

import cn.schoolwow.quickflow.domain.FlowContext;
import cn.schoolwow.quickflow.flow.BusinessFlow;
import cn.schoolwow.util.module.query.queryPackage.domain.QueryPackageOption;
import org.apache.commons.lang3.StringUtils;

import java.io.File;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

public class GetClassNameListByPackageNameFlow implements BusinessFlow {
    @Override
    public void executeBusinessFlow(FlowContext flowContext) throws Exception {
        QueryPackageOption queryPackageOption = flowContext.checkInstanceData(QueryPackageOption.class);

        String packageNamePath = queryPackageOption.packageName.replace(".", "/");
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        URL url = classLoader.getResource(packageNamePath);
        if(null==url){
            flowContext.broken("包路径不存在");
        }
        flowContext.putInstanceData(url, URL.class);

        List<String> classNameList = new ArrayList<>();
        flowContext.putCurrentFlowData("packageNamePath", packageNamePath);
        flowContext.putCurrentFlowData("classNameList", classNameList);

        switch (url.getProtocol()) {
            case "file": {
                getFromFile(flowContext);
            }
            break;
            case "jar": {
                getFromJar(flowContext);
            }
            break;
        }
        if(classNameList.isEmpty()){
            flowContext.broken("指定包下面不存在类");
        }
        flowContext.putTemporaryData("classNameList", classNameList);
    }

    @Override
    public String name() {
        return "根据包名获取类名列表";
    }

    private void getFromFile(FlowContext flowContext) throws IOException {
        URL url = flowContext.checkInstanceData(URL.class);
        QueryPackageOption queryPackageOption = flowContext.checkInstanceData(QueryPackageOption.class);
        List<String> classNameList = flowContext.getData("classNameList", List.class);

        File file = new File(url.getFile());
        //TODO 对于有空格或者中文路径会无法识别
        if (!file.isDirectory()) {
            throw new IllegalArgumentException("包名不是合法的文件夹!" + url.getFile());
        }
        String indexOfString = queryPackageOption.packageName.replace(".", "/");
        Files.walkFileTree(file.toPath(), new SimpleFileVisitor<Path>() {
            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                File f = file.toFile();
                if (f.getName().endsWith(".class")) {
                    String path = f.getAbsolutePath().replace("\\", "/");
                    int startIndex = path.indexOf(indexOfString);
                    String className = path.substring(startIndex, path.length() - 6).replace("/", ".");

                    if(StringUtils.isNotBlank(queryPackageOption.classNamePrefix)&&!className.startsWith(queryPackageOption.classNamePrefix)){
                        return FileVisitResult.CONTINUE;
                    }
                    if(StringUtils.isNotBlank(queryPackageOption.classNameSuffix)&&!className.endsWith(queryPackageOption.classNameSuffix)){
                        return FileVisitResult.CONTINUE;
                    }
                    classNameList.add(className);
                }
                return FileVisitResult.CONTINUE;
            }
        });
    }

    private void getFromJar(FlowContext flowContext) throws IOException {
        URL url = flowContext.checkInstanceData(URL.class);
        List<String> classNameList = flowContext.getData("classNameList", List.class);
        String packageNamePath = flowContext.checkData("packageNamePath", String.class);
        QueryPackageOption queryPackageOption = flowContext.checkInstanceData(QueryPackageOption.class);

        JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection();
        if (null != jarURLConnection) {
            JarFile jarFile = jarURLConnection.getJarFile();
            if (null != jarFile) {
                Enumeration<JarEntry> jarEntries = jarFile.entries();
                while (jarEntries.hasMoreElements()) {
                    JarEntry jarEntry = jarEntries.nextElement();
                    String jarEntryName = jarEntry.getName();
                    if (jarEntryName.contains(packageNamePath) && jarEntryName.endsWith(".class")) { //是否是类,是类进行加载
                        String className = jarEntryName.substring(0, jarEntryName.lastIndexOf(".")).replaceAll("/", ".");
                        if(StringUtils.isNotBlank(queryPackageOption.classNamePrefix)&&!className.startsWith(queryPackageOption.classNamePrefix)){
                            continue;
                        }
                        if(StringUtils.isNotBlank(queryPackageOption.classNameSuffix)&&!className.endsWith(queryPackageOption.classNameSuffix)){
                            continue;
                        }
                        classNameList.add(className);
                    }
                }
            }
        }
    }
}
